var __forceExit = false;
window.onbeforeunload = function(/*e*/) {
    __forceExit = true;
    /*
     if(!e) e = window.event;
     //e.cancelBubble is supported by IE - this will kill the bubbling process.
     e.cancelBubble = true;
     e.returnValue = "Ao sair as informações não salvas serão perdidas."; //This is displayed on the dialog
     
     //e.stopPropagation works in Firefox.
     if (e.stopPropagation) {
     e.stopPropagation();
     e.preventDefault();
     }*/
};

/**
 * @var class Zf2.Ajax
 */
Zf2.Ajax = function()
{
    var self = this;

    var _url = "";
    var _data = null;
    var _type = "POST";
    var _dataType = "json";
    var _async = true;
    var _showLoading = true;
    var _cache = true;
    var _contentType = "application/x-www-form-urlencoded; charset=UTF-8";
    var _processData = true;
    var _callback = null;
    var _callbackSuccess = null;
    var _callbackError = null;
    var _ssl = false;
    var _fileUpload = false;
    var _result = {};

    var _loading = Zf2.loading();

    /**
     * @type Boolean
     */
    this.completed = false;

    /**
     * @param {object} result
     * @returns {undefined}
     */
    var _setResult = function(result)
    {
        _result = result;
    };

    /**
     * @returns {undefined}
     */
    var _onBeforeSend = function()
    {
        Core.console.debug("Zf2.Ajax(): onBeforeSend", Core.console.type.INFO);
        if (_showLoading === true) {
            _loading.show();
        }
    };

    /**
     * @returns {undefined}
     */
    var _onComplete = function()
    {
        Core.console.debug("Zf2.Ajax(): onComplete", Core.console.type.INFO);
        _loading.close();

        if (self.completed === true) {
            Core.console.debug("Zf2.Ajax(): callback com o result", Core.console.type.INFO);
            Core.callbackHandler(_callback, self.getResult());
        } else {
            Core.console.debug("Zf2.Ajax(): completou mais não completou =)", Core.console.type.INFO);
        }
    };

    /**
     * @param {object} response
     * @returns {undefined}
     */
    var _onSuccess = function(response)
    {
        Core.console.debug("Zf2.Ajax(): onSuccess", Core.console.type.INFO);
        try {
            self.completed = true;
            _setResult(response);
            if (_dataType === 'text') {
                response = json_decode(response);
            }
            if (typeof (response) === "object") {
                if (!is_null(response) && isset(response.type)) {
                    switch (self.responseHandle(response)) {
                        case 'errorAcl':
                        case 'errorValidate':
                        case 'warning':
                        case 'error':
                            self.completed = false;
                            break;
                        case 'success':
                            _setResult(response.data);
                            break;
                        default:
                            throw new Core.Exception("Zf2.Ajax.onSuccess(): 'type' inválido");
                            break;
                    }
                }
            } else {
                throw new Core.Exception("Zf2.Ajax.onSuccess(): Retorno não é um JSON");
            }
        } catch (e) {
            self.completed = false;
            Core.exceptionHandler(e);
        }
    };

    /**
     * @param {object} XMLHttpRequest
     * @param {string} textStatus
     * @param {string} errorThrown
     * @returns {undefined}
     */
    var _onError = function(XMLHttpRequest, textStatus, errorThrown)
    {
        Core.console.debug("Zf2.Ajax(): onError", Core.console.type.INFO);
        self.completed = false;
        _onComplete();

        self.errorHandle(XMLHttpRequest, textStatus, errorThrown);
    };

    /**
     * @param {object} options
     * @returns {string} HTML
     */
    this.loadAction = function(options)
    {
        try {
            options = options || {};
            if (typeof (options) !== "object") {
                throw new Core.Exception("Zf2.Ajax.loadAction(): Passe as opções corretamente");
            } else if (empty(options)) {
                throw new Core.Exception("Zf2.Ajax.loadAction(): Preencha as opções");
            }
            if (isset(options.container)) {
                if (typeof (options.container) === "string") {
                    options.container = $(options.container);
                }
                if (options.container.length === 0) {
                    throw new Core.Exception("Zf2.Ajax.loadAction(): opção 'container' não é um ID / Objeto jQuery válido!")
                }
                var callback = options.callback;
                options.callback = function(result) {
                    options.container.html(result);
                    Core.callbackHandler(callback, result);
                    Zf2.form.setupInputs(options.container);
                    Core.callbackHandler(options.afterShow);
                };
            }
            options.dataType = "text";
            self.submit(options);
        } catch (e) {
            Core.exceptionHandler(e);
        }
    };

    /**
     * @return {object}
     */
    this.getResult = function()
    {
        return _result;
    };

    /**
     * @param {object} options
     *    action          : string                   : Action da url. Caso não passada pega a mesma
     *
     *    controller      : string                   : Controller da url. Caso não passada pega o mesmo
     *
     *    module          : string                   : Module da url. Caso não passada pega o mesmo
     *
     *    data            : mixed                    : Os dados que serão postados
     *
     *    type            : string                   : Tipo de requisição. O padrão é "POST"
     *
     *    dataType        : string                   : Tipo de dados retornado. O padrão é "json"
     *
     *    async           : boolean                  : Por padrão é true para não 'travar' a execução do javascript
     *                                                 para capturar o retorno da requisição sugere-se declarar a
     *                                                 function do paramêtro 'callback' onde recebe como argumento
     *                                                 o resultado da requisição
     *
     *    callback        : function( ajaxResult ){} : função que é chamada ao terminar a requisição com o resultado
     *
     *    callbackSuccess : function( result ){}     : função que é chamada ao terminar a requisição com sucesso com o resultado
     *
     *    callbackError   : function(){}             : função que é chamada ao terminar a requisição com erro
     *
     * @returns {undefined}
     */
    this.submit = function(options)
    {
        
        try {
            options = options || {};

            if (typeof (options) !== "object") {
                throw new Core.Exception("Zf2.Ajax.submit(): Passe as opções corretamente");
            } else if (empty(options)) {
                throw new Core.Exception("Zf2.Ajax.submit(): Preencha as opções");
            }

            _url = Core.mountUrl(options);
            

            _data = isset(options.data) ? options.data : _data;
            _type = isset(options.type) ? options.type : _type;
            _contentType = isset(options.contentType) ? options.contentType : _contentType;
            _processData = isset(options.processData) ? options.processData : _processData;
            _cache = isset(options.cache) ? options.cache : _cache;
            _dataType = isset(options.dataType) ? options.dataType : _dataType;
            _async = isset(options.async) ? options.async : _async;
            _showLoading = isset(options.showLoading) ? options.showLoading : _showLoading;
            _callback = isset(options.callback) ? options.callback : _callback;
            _callbackSuccess = isset(options.callbackSuccess) ? options.callbackSuccess : _callbackSuccess;
            _callbackError = isset(options.callbackError) ? options.callbackError : _callbackError;
            _ssl = isset(options.ssl) ? options.ssl : _ssl;
            _fileUpload = isset(options.fileUpload) ? options.fileUpload : _fileUpload;
            if (typeof (_async) !== "boolean") {
                throw new Core.Exception("Zf2.Ajax.submit(): Opção 'async' tem que ser true ou false");
            }

            if (typeof (_data) === "string") {
                _data = $(_data);
            }

            if (_data === null) {
                _data = $(':input').not(':disabled,:button');
            }

            if (isset(_data.jquery)) {
                if (!_data.is(':input')) {
                    _data = _data.find(':input').not(':disabled,:button');
                }

                
                _data = _data.serialize();
                

            }
            
            $.ajax({
                "url": _url,
                "data": _data,
                "cache": _cache,
                "contentType": _contentType,
                "processData": _processData,
                "type": _type,
                "dataType": _dataType,
                "async": _async,
                "error": _onError,
                "success": _onSuccess,
                "complete": _onComplete,
                "beforeSend": _onBeforeSend
            });
        } catch (e) {
            Core.exceptionHandler(e);
        }
    };

    /**
     * @param {object} XMLHttpRequest
     * @param {string} textStatus
     * @param {string} errorThrown
     * @returns {undefined}
     */
    this.errorHandle = function(XMLHttpRequest, textStatus, errorThrown)
    {
        Core.console.group("Erro no AJAX", true);
        Core.console.debug(textStatus, 'textStatus', Core.console.type.WARN);
        Core.console.debug(errorThrown, 'errorThrown', Core.console.type.WARN);
        Core.console.debug(XMLHttpRequest, 'XMLHttpRequest', Core.console.type.ERROR);
        Core.console.groupEnd();


        if (__forceExit !== true) {
            Zf2.messageBox.critical({
                "message": 'Erro de sistema',
                "details": errorThrown
            });
        } else {
            Core.console.debug('FORCE EXIT', '', Core.console.type.ERROR);
        }
    };

    /**
     * @param {object} response
     * @returns {string}
     */
    this.responseHandle = function(response)
    {
        switch (response.type) {
            case 'errorAcl':
                Core.console.group("Acl error: " + _url, true);
                Core.console.debug(response);
                Core.console.groupEnd();


                Zf2.messageBox.critical({
                    "message": 'Sem permissão de acesso',
                    "details": response.message
                });
                break;
            case 'errorValidate':
                Core.console.group("Validate error: " + _url, true);
                Core.console.debug(response);
                Core.console.groupEnd();

                try {
                    Core.form.validateErrorHandler(response);
                } catch (e) {
                    Core.exceptionHandler(e);
                }
                break;
            case 'error':
                Core.console.group("Error: " + _url, true);
                Core.console.debug(response);
                Core.console.groupEnd();

                Zf2.messageBox.critical({
                    "message": response.message,
                    "details": response.details,
                    "callback": function() {
                        Core.callbackHandler(_callbackError, response.data);
                    }
                });

                break;
            case 'warning':
                Core.console.group("Error: " + _url, true);
                Core.console.debug(response);
                Core.console.groupEnd();

                Zf2.messageBox.warning({
                    "message": response.message,
                    "details": response.details,
                    "callback": function() {
                        Core.callbackHandler(_callbackError, response.data);
                    }
                });

                break;
            case 'success':
                Core.console.group("Success: " + _url);
                Core.console.debug("Message: " + response.message, '', Core.console.type.INFO);
                Core.console.group("Data:", true);
                Core.console.debug(response.data);
                Core.console.groupEnd();
                Core.console.groupEnd();


                if ($.trim(response.message) !== '') {
                    Zf2.messageBox.success({
                        "message": response.message,
                        "callback": function() {
                            Core.callbackHandler(_callbackSuccess, response.data);
                        }
                    });
                } else {
                    Core.callbackHandler(_callbackSuccess, response.data);
                }
                break;
            default:
                break;
        }

        return response.type;
    };

    return this;
};